home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / dtr / audio.c next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  12.7 KB  |  429 lines

  1. /*
  2.  * Copyright (c) 1990, 1991 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and 
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that (i) the above copyright notices and this permission notice appear in
  7.  * all copies of the software and related documentation, and (ii) the name
  8.  * Stanford may not be used in any advertising or publicity relating to
  9.  * the software without the specific, prior written permission of
  10.  * Stanford.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  15.  *
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
  19.  * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
  20.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21.  * SOFTWARE.
  22.  */
  23.  
  24. /* $Header: /Source/Media/collab/DTR/RCS/audio.c,v 1.10 92/01/09 12:39:45 drapeau Exp Locker: derek $ */
  25. /* $Log:    audio.c,v $
  26.  * Revision 1.10  92/01/09  12:39:45  drapeau
  27.  * Slight modifications to the code to make it ANSI-compliant.
  28.  * 
  29.  * Revision 1.0  92/01/06  17:37:18  drapeau
  30.  * Cosmetic changes to make code easier to read and to conform to
  31.  * programming specifications.
  32.  * 
  33.  * Revision 0.25  91/09/18  22:46:22  derek
  34.  * The following things are done:
  35.  * 1.    The Makefile is changed corresponding to the changes in collab/.
  36.  * 2.    Copyright messages included.
  37.  * 3.    Some minor bugs fixed.
  38.  * 
  39.  * Revision 0.24  91/08/21  11:28:41  derek
  40.  * The following changes are made:
  41.  * 1.    Now the duration and size of the recorded sound will be displayed
  42.  *     during recording.
  43.  * 2.    I have changed GetSelection() corresponding to the request of Tek joo
  44.  * 3.    Info Panel is added to the application.
  45.  * 4.    Fixed SizeToFitHandler() so that when no file or buffer is currently
  46.  *     loaded, it would not do anything (except giving a warning
  47.  *     notice_prompt).
  48.  * 5.    Inplemented the `Close' Menu option in the document menu.
  49.  * 6.    Fixed the bug in which after ClearAll and I press PreviewEdit,
  50.  *     the edit wont be played.
  51.  * 7.    I have made the changes corresponding to the change in OpenPanel's
  52.  *     name.  (from OpenPanel to Browse).
  53.  * 8.    Incorporated BrowseCheck to check command line arg.
  54.  * 9.    Changed most EditingStatusMessages to NoticePrompts.
  55.  * 10.    SoundFileSaveAsPopUp and EditListSaveAsPopUp are removed 
  56.  *     from the application.
  57.  * 
  58.  * Revision 0.23  91/08/14  16:13:29  derek
  59.  * Fixed a few saving/appending bugs.
  60.  * 
  61.  * Revision 0.22  91/08/13  20:35:28  derek
  62.  * The buttons (play, pause, record) will now flash after they are pressed.
  63.  * This only applies to times when audio files (not edit-lists) are 
  64.  * played.
  65.  * 
  66.  * Revision 0.21  91/08/08  10:59:53  derek
  67.  * This is a cleaner version.  I have removed lots of printf/fprintf 
  68.  * statements from it, and have also cleaned up the code using xsaber.
  69.  * This version should run substantially faster.
  70.  * 
  71.  * Revision 0.20  91/08/07  16:22:40  derek
  72.  * The Edit list part of DTR is done.  OpenPanel is also incorporated.
  73.  * 
  74.  * Revision 0.19  91/08/06  12:40:25  derek
  75.  * Edit list panel is done.  Still need to link it to the network code.
  76.  * 
  77.  * Revision 0.18  91/07/31  14:49:27  derek
  78.  * I have changed the user interface so that text fields like size and
  79.  * duration will be displayed in normal (not bold) format.   I also fixed
  80.  * a network bug.  In addition, I have added a routine to check how
  81.  * much disk space is left in /usr/tmp.
  82.  * 
  83.  * Revision 0.17  91/07/29  15:09:33  derek
  84.  * The playing w/o stopping error is fixed.
  85.  * 
  86.  * Revision 0.16  91/07/27  11:44:43  derek
  87.  * I have added audio output options to the application.  User can choose
  88.  * either headphone or speaker as output device.
  89.  * 
  90.  * Revision 0.15  91/07/24  12:50:08  derek
  91.  * Disk editing is done.  Now the application can record sound infinitely,
  92.  * as long as there is disk space available.  Command line args are also
  93.  * supported.
  94.  * 
  95.  * Revision 0.14  91/07/23  21:16:57  derek
  96.  * This version is not ready for release.  Disk space editing is half-done:
  97.  * the application can play an infinite sound and the canvases can handle
  98.  * infinite sound files.  The app is pretty bug free too, I think.  The
  99.  * weakness is that it cannot record sound infinitely.  
  100.  * 
  101.  * Revision 0.13  91/06/26  15:54:26  derek
  102.  * I have reformatted the code to conform coding specs.
  103.  * 
  104.  * Revision 0.12  91/06/20  19:53:53  derek
  105.  * The network part should be working.  Also fixed numerous minor parts
  106.  * involving the canvas and the display.
  107.  * 
  108.  * Revision 0.10  1991/04/25  01:42:30  derek
  109.  * This version is checked in on 4/24/91
  110.  * */
  111. static char rcsid[] = "$Header: /Source/Media/collab/DTR/RCS/audio.c,v 1.10 92/01/09 12:39:45 drapeau Exp Locker: derek $";
  112.  
  113. #include "dtr.h"
  114. #include "dtr_ui.h"
  115.  
  116. void
  117.   InitAudio()
  118. {
  119.   extern  dtr_mainWindow_objects *dtr_mainWindow;
  120.  
  121.   EVENT("Init_Audio");
  122.   
  123.   Audioctl_fd = -1;    
  124.   Audio_fd = -1;
  125.   Sync_sched = FALSE;
  126.  
  127.   xv_set(dtr_mainWindow->playGain,
  128.      PANEL_NOTIFY_LEVEL, PANEL_ALL, NULL);
  129.   xv_set(dtr_mainWindow->recordGain,
  130.      PANEL_NOTIFY_LEVEL, PANEL_ALL, NULL);
  131. }
  132.  
  133.  
  134. /*
  135.  * Open audio control device (/dev/audioctl) and read its state.
  136.  * This may be used for state get/set (eg, volume levels) without holding
  137.  * the main audio device (/dev/audio) open.
  138.  */
  139. void
  140.   InitAudioControl()
  141. {
  142.   EVENT("Init_Audio_Control");
  143.   if ((Audioctl_fd = open(AUDIO_CTLDEV, O_RDWR)) < 0)            /*  Open audio control device  */
  144.   {
  145.     PERROR(AUDIO_CTLDEV);                        /*  If audioctl device cannot be opened, ...        */
  146.     Device_phdr.sample_rate = 8000;                    /*  ... initialize the audio header to default ...  */
  147.     Device_phdr.channels = 1;                        /*  ... value.                                      */
  148.     Device_phdr.bytes_per_unit = 1;
  149.     Device_phdr.samples_per_unit = 1;
  150.     Device_phdr.encoding = AUDIO_ENCODING_ULAW;
  151.     Device_rhdr = Device_phdr;
  152.     Buffer.hdr = Device_phdr;
  153.   } 
  154.   else 
  155.   {
  156.     if (ioctl(Audioctl_fd, I_SETSIG, S_MSG) < 0)            /*  Tell the driver to send SIGPOLL on device ...   */
  157.       PERROR("Could not issue I_SETSIG ioctl");                /*  ... state changes.                              */
  158.     
  159.     if ((audio_get_play_config(Audioctl_fd, &Device_phdr) !=        /*  Get the device play and record ...              */
  160.      AUDIO_SUCCESS) ||                        /*  ... configuration ie. get the current ...       */
  161.     (audio_get_record_config(Audioctl_fd, &Device_rhdr) !=      /*  ... status of the device.                       */
  162.      AUDIO_SUCCESS)) 
  163.     {
  164.       PERROR("Could not get encoding configuration");
  165.     }
  166.   }
  167.   AUDIO_INITINFO(&Audio_state);
  168. }                                    /* end function InitAudioControl */
  169.  
  170.  
  171. /*
  172.  * Open the audio device, using the Active_flag to derive open modes.
  173.  * Returns:
  174.  *    0    Successful open
  175.  *    1    Audio device is busy (try again later)
  176.  *    -1    Error during open
  177.  */
  178. int
  179.   AudioOpen(flag)
  180. int    flag;
  181. {
  182.   EVENT("Audio_Open");
  183.   
  184.   if (Audio_fd >= 0) 
  185.   {                                    /*  already open.  */
  186.     fprintf(stderr, "%s already open\n", AUDIO_DEV);
  187.     return (-1);
  188.   }
  189.   
  190.   flag = ((flag & RECORD) ? O_RDONLY : O_WRONLY) | O_NDELAY;        /*  Read-only access if Record.   Write-only if ... */
  191.                                     /*  ... Play or Alert.                              */
  192.   if ((Audio_fd = open(AUDIO_DEV, flag)) < 0) 
  193.   {
  194.     if ((errno == EINTR) || (errno == EBUSY))
  195.       return (1);
  196.     PERROR(AUDIO_DEV);
  197.     return (-1);
  198.   }
  199.   
  200.   flag = fcntl(Audio_fd, F_GETFL, 0) | FNDELAY;                /*  Set up for asynchronous, non-blocking i/o.      */
  201.   if (fcntl(Audio_fd, F_SETFL, flag) < 0)
  202.     PERROR("F_SETFL fcntl");
  203.   if (ioctl(Audio_fd, I_SETSIG, S_INPUT|S_OUTPUT|S_MSG) < 0)
  204.     PERROR("I_SETSIG ioctl");
  205.   return (0);
  206. }
  207.  
  208.  
  209. /*
  210.  * Convert local gain into device parameters 
  211.  */
  212. double
  213.   ScaleGain(g)
  214. int g;
  215. {
  216.   return((double)g/(double)MAX_GAIN);
  217. }
  218.  
  219.  
  220. /*
  221.  *  Convert device gain into the local scaling factor
  222.  */
  223. int
  224.   UnscaleGain(g)
  225. double        g;
  226. {
  227.   return (irint((double)MAX_GAIN * g));
  228. }
  229.  
  230. /*
  231.  * Read the audio device state and translate fields into 
  232.  * values we understand.
  233.  */
  234. BOOL
  235.   AudioReadState(aip)
  236. Audio_info    *aip;
  237. {
  238.   extern  dtr_mainWindow_objects *dtr_mainWindow;
  239.  
  240.   EVENT("Audio_Read_State");
  241.   if ((Audioctl_fd > 0) &&
  242.       (audio_getinfo(Audioctl_fd, aip) != AUDIO_SUCCESS)) 
  243.   {                                    /*  If error, quit trying to access control device. */
  244.     Audioctl_fd = -1;
  245.     AlertByNoticePrompt(dtr_mainWindow->menuControlPanel,
  246.             "Error: audio control device error.");
  247.   }
  248.   
  249.   if (Audioctl_fd < 0) 
  250.   {                                    /*  Set dummy values.  */
  251.     aip->play.gain = 35;
  252.     aip->record.gain = 60;
  253.     aip->play.port = 0;
  254.     aip->play.eof = 0;
  255.     aip->play.error = FALSE;
  256.     aip->play.pause = FALSE;
  257.     aip->record.error = FALSE;
  258.     aip->record.pause = FALSE;
  259.     return (FALSE);
  260.   }
  261.   
  262.   aip->play.gain = UnscaleGain((double)(aip->play.gain -        /*  Convert to values that we understand.           */
  263.                     AUDIO_MIN_GAIN) /
  264.                    (double)AUDIO_MAX_GAIN);
  265.   aip->record.gain = 
  266.     UnscaleGain((double)(aip->record.gain - AUDIO_MIN_GAIN) /
  267.         (double)AUDIO_MAX_GAIN);
  268.   
  269.   aip->play.port = (unsigned) ((aip->play.port == AUDIO_SPEAKER) ? 0 : 1);
  270.   return (TRUE);
  271. }
  272.  
  273.  
  274. void
  275.   AudioUpdatePanel(init)
  276. int    init;
  277. {
  278.   Audio_info    Audio_new;
  279.   
  280.   EVENT("Audio_Update_Panel");
  281.   
  282.   if (!AudioReadState(&Audio_new) && !init)
  283.     return;
  284.   
  285.   if (ActiveFlag & PLAY)
  286.     Buffer.paused = Audio_new.play.pause;
  287.   if (ActiveFlag & RECORD)
  288.     Buffer.paused = Audio_new.record.pause;
  289.   
  290.   if (!ActiveFlag)                            /*  if not active, assume pause state only if...    */
  291.   {                                    /*  ...both flags set.                              */
  292.     Buffer.paused = Audio_new.play.pause && Audio_new.record.pause;
  293.   } 
  294.   else if (ActiveFlag & PLAY) 
  295.   {
  296.     if (Buffer.paused)                            /*  put in timer and screen update routines.        */
  297.     {
  298.       CancelVUMeterTimer();
  299. /*      CancelButtonGlowTimer();*/
  300.     }
  301.     else
  302.     {
  303.       SetVUMeterTimer((double)SCOPE_WIDTH/(double)Buffer.hdr.sample_rate);
  304. /*      SetButtonGlowTimer(GLOW_INTERVAL);*/
  305.     }
  306.   }
  307.   Audio_new.play.pause = Buffer.paused;
  308.   Audio_state = Audio_new;
  309. }                                    /* end function AudioUpdatePanel */
  310.  
  311.  
  312. Notify_value
  313.   SigpollAsyncHandler(client, sig, when)
  314. Notify_client        client;
  315. int            sig;
  316. Notify_signal_mode    when;
  317. {
  318.   int            save_errno;
  319.   
  320.   EVENT("Sigpoll_Async_Handler");
  321.   
  322.   save_errno = errno;                            
  323.   
  324.   if (!WaitFlag) 
  325.   {                                    /*  Device is open.  Attempt to keep queues filled. */
  326.     if (ActiveFlag & PLAY)
  327.       PlayService();
  328.     if (ActiveFlag & RECORD)
  329.     {
  330.       RecordService();
  331.     }
  332.   }
  333.   
  334.   if (!Sync_sched)                            /*  SIGPOLL is also sent if the state of the...     */
  335.   {                                    /*  ...device is changed.  Schedule the...          */
  336.     Sync_sched = TRUE;                            /*  ...synchronous handler, unless it was...        */
  337.     (void) notify_post_event(SIGPOLL, NULL, NOTIFY_SAFE);        /*  ...already scheduled.                           */
  338.   }
  339.   
  340.   errno = save_errno;        
  341.  
  342.   UpdateRecordingMessageDisplay();
  343.  
  344.   return (NOTIFY_DONE);
  345. }
  346.  
  347.  
  348. /*
  349.  * Synchronous SIGPOLL handler...entered when the asynchronous SIGPOLL
  350.  * handler detects something to do synchronously, like updating displays.
  351.  */
  352. Notify_value
  353.   SigpollSyncHandler(client, event, arg, when)
  354. Notify_client        client;
  355. Notify_event        event;
  356. Notify_arg        arg;
  357. Notify_event_type    when;
  358. {
  359.   EVENT("Sigpoll_Sync_Handler");
  360.   
  361.   Sync_sched = FALSE;                            /*  flag to async handler.  */
  362.   
  363.   /* Waiting for the device open to succeed */
  364.   if (WaitFlag)
  365.   {
  366.     if (!AudioOpen(WaitFlag)) 
  367.     {                                    /*  device is open...start transfers.  */
  368.       if (WaitFlag & PLAY) 
  369.       {
  370.     WaitFlag &= ~PLAY;
  371.     StartPlay();
  372.       }
  373.       if (WaitFlag & RECORD) 
  374.       {
  375.     WaitFlag &= ~RECORD;
  376.     StartRecord();
  377.       }
  378.     }
  379.   } 
  380.   
  381.   AudioUpdatePanel(FALSE);
  382.   
  383.   if ((ActiveFlag & PLAY) && Audio_state.play.eof &&            /*  Detect whether output is complete.  The...      */
  384.       Buffer.draining)                            /*  ...play.eof flag is incremented when a...       */
  385.   {                                    /*  ...zero-length write has been processed.        */
  386.     StopPlay();                                /*  Output draining is complete.                    */
  387.     
  388. #ifdef notdef
  389.     if (Audio_state.play.error) 
  390.     {
  391.       AlertByNoticePrompt(dtr_mainWindow->menuControlPanel,
  392.               "Underflow detected during Play.");
  393.     }
  394. #endif
  395.   }
  396.   return (NOTIFY_DONE);
  397. }
  398.  
  399.  
  400. /* 
  401.  *  Flush queued output and close the audio device.
  402.  */
  403. void
  404.   AudioFlushClose()
  405. {
  406.   EVENT("Audio_Flush_Close");
  407.   
  408.   if (Audio_fd < 0)
  409.     return;
  410.   (void) audio_flush(Audio_fd);
  411.   (void) close(Audio_fd);
  412.   Audio_fd = -1;
  413. }
  414.  
  415.  
  416. void
  417.   SetPlayGain(volume)
  418. int    volume;
  419. {
  420.   extern   dtr_mainWindow_objects   *dtr_mainWindow;
  421.   double   gain;
  422.  
  423.   xv_set(dtr_mainWindow->playGain, PANEL_VALUE, volume, NULL);
  424.   gain = ScaleGain(volume);
  425.   Audio_state.play.gain = ~0;
  426.   (void) audio_set_play_gain(Audioctl_fd, &gain);
  427. }
  428.   
  429.